package com.express.service.impl;

import com.baomidou.dynamic.datasource.annotation.DS;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.express.dto.ApiClassDto;
import com.express.dto.ApiDto;
import com.express.dto.ApiFormDto;
import com.express.entity.*;
import com.express.mapper.*;
import com.express.service.*;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import org.springframework.transaction.annotation.Transactional;

import java.util.ArrayList;
import java.util.Date;
import java.util.List;

/**
 * 系统api
 *
 * @author Rock.Zhou
 * @email cool_fish@aliyun.com
 * @date 2020-01-18 20:07:56
 */
@Service("sysApiService")
public class SysApiServiceImpl extends ServiceImpl<SysApiDao, SysApiEntity> implements SysApiService {

    /**
     * api分类
     */
    @Autowired
    private SysApiClassDao apiClassDao;

    /**
     * api
     */
    @Autowired
    private SysApiDao apiDao;

    /**
     * api请求头
     */
    @Autowired
    private SysApiRequestHeadersDao apiRequestHeadersDao;

    /**
     * api 请求参数
     */
    @Autowired
    private SysApiRequestQueryDao apiRequestQueryDao;

    /**
     * api请求体
     */
    @Autowired
    private SysApiRequestBodyDao apiRequestBodyDao;

    /**
     * api 响应body
     */
    @Autowired
    private SysApiResponseDao apiResponseDao;

    /**
     * 用户接口关联表
     */
    @Autowired
    private SysUserApiDao userApiDao;

    /**
     * 根据用户id获取api菜单
     *
     * @param userId
     * @return
     */
    @DS("api")
    @Override
    public List<ApiClassDto> getApiListByUserId(long userId) {
        // 返回列表
        List<ApiClassDto> reList = new ArrayList<>();
        // 获取所有api分类
        List<SysApiClassEntity> apiClassList = apiClassDao.selectList(new QueryWrapper<SysApiClassEntity>()
                .ne("is_del", 1)
                .eq("status", 1));
        // 根据用户获取所有api
        List<SysApiEntity> apiList = apiDao.selectListByUserId(userId);

        // api分类
        apiClassList.forEach(apiClass -> {
            ApiClassDto apiClassDto = new ApiClassDto();
            apiClassDto.setApiClassId(apiClass.getId());
            apiClassDto.setApiClassName(apiClass.getApiClassName());
            List<ApiDto> apiDtoList = new ArrayList<>();

            Long apiClassId = apiClass.getId();
            // 遍历api列表
            apiList.forEach(api -> {
                if (null != api.getApiClassId() && apiClassId.equals(api.getApiClassId())) {
                    ApiDto apiDto = new ApiDto();
                    apiDto.setApiId(api.getId());
                    apiDto.setApiName(api.getApiName());
                    apiDto.setApiUrl(api.getApiUrl());

                    apiDtoList.add(apiDto);
                }
            });
            apiClassDto.setApiDtoList(apiDtoList);
            reList.add(apiClassDto);
        });

        // 删除为空的apiClassDto
        for (int i = 0; i < reList.size(); i++) {
            ApiClassDto apiClassDto = reList.get(i);
            if (apiClassDto.getApiDtoList().size() < 1) {
                reList.remove(i);
            }
        }


        return reList;
    }

    /**
     * 新增一个api详情表单
     *
     * @param apiFormDto
     * @return
     */
    @DS("api")
    @Transactional(rollbackFor = Exception.class)
    @Override
    public Long saveApiForm(ApiFormDto apiFormDto) {

        // 拆分实体类
        SysApiEntity apiEntity = this.getSysApiEntity(apiFormDto);

        // apiId
        Long apiId;

        // api插入 返回apiId
        int apiInsert = apiDao.insertOne(apiEntity);
        if (apiInsert == 1 && apiEntity.getId() > 0) {
            apiId = apiEntity.getId();
        } else {
            // 手动抛异常触发回滚
            throw new RuntimeException();
        }

        // api 请求参数插入
        if (null != apiFormDto.getRequestQueryList() && apiFormDto.getRequestQueryList().size() > 0) {
            List<SysApiRequestQueryEntity> requestQueryList = apiFormDto.getRequestQueryList();
            requestQueryList.forEach(requestQuery -> requestQuery.setApiId(apiId));

            int requestQueryInsert = apiRequestQueryDao.insertList(requestQueryList);
            if (requestQueryInsert < 1) {
                throw new RuntimeException();
            }
        }

        // api 请求头插入
        if (null != apiFormDto.getRequestHeadersList() && apiFormDto.getRequestHeadersList().size() > 0) {
            List<SysApiRequestHeadersEntity> requestHeadersList = apiFormDto.getRequestHeadersList();
            requestHeadersList.forEach(requestHeaders -> requestHeaders.setApiId(apiId));

            int requestHeadersInsert = apiRequestHeadersDao.insertList(requestHeadersList);
            if (requestHeadersInsert < 1) {
                throw new RuntimeException();
            }
        }

        // api 请求体插入
        if (null != apiFormDto.getRequestBodyList() && apiFormDto.getRequestBodyList().size() > 0) {
            List<SysApiRequestBodyEntity> requestBodyList = apiFormDto.getRequestBodyList();
            requestBodyList.forEach(requestBody -> requestBody.setApiId(apiId));

            // 遍历最外层集合
            requestBodyList.forEach(requestBody -> {
                // 如果有下级节点，强制将类型改成object
                if (null != requestBody.getChildren() && requestBody.getChildren().size() > 0) {
                    requestBody.setBodyType("object");
                }
                // 存入，自动返回主键
                int i = apiRequestBodyDao.insertOne(requestBody);
                if (i < 1) {
                    throw new RuntimeException();
                }
                // 插入下级节点
                if (null != requestBody.getChildren() && requestBody.getChildren().size() > 0) {
                    this.saveRequestBodyChildren(requestBody, apiId);
                }
            });
        }

        // api 响应body插入
        if (null != apiFormDto.getResponseList() && apiFormDto.getResponseList().size() > 0) {
            List<SysApiResponseEntity> responseList = apiFormDto.getResponseList();
            responseList.forEach(response -> response.setApiId(apiId));

            // 遍历最外层集合
            responseList.forEach(responseBody -> {
                // 判断是否有下级节点，强制将类型改成object
                if (null != responseBody.getChildren() && responseBody.getChildren().size() > 0) {
                    responseBody.setResponseType("object");
                }
                // 存入，自动返回主键
                int i = apiResponseDao.insertOne(responseBody);
                if (i < 1) {
                    throw new RuntimeException();
                }
                // 插入下级节点
                if (null != responseBody.getChildren() && responseBody.getChildren().size() > 0) {
                    // 获取上级主键
                    this.saveResponseChildren(responseBody, apiId);
                }
            });
        }
        return apiId;
    }

    /**
     * 递归插入requestBody下级节点
     *
     * @param requestBody
     * @param apiId
     */
    @Transactional(rollbackFor = Exception.class)
    public void saveRequestBodyChildren(SysApiRequestBodyEntity requestBody, Long apiId) {
        // 插入下级节点
        if (null != requestBody.getChildren() && requestBody.getChildren().size() > 0) {
            // 获取上级主键
            Long id = requestBody.getId();
            List<SysApiRequestBodyEntity> list = requestBody.getChildren();
            // 遍历所有下级节点
            list.forEach(one -> {
                // 存入上级节点id 和 apiId
                one.setParentId(id);
                one.setApiId(apiId);
                // 插入下级节点
                int insertOneCount = apiRequestBodyDao.insertOne(one);
                if (insertOneCount < 1) {
                    throw new RuntimeException();
                }
                // 判断递归出口
                if (null != one.getChildren() && requestBody.getChildren().size() > 0) {
                    saveRequestBodyChildren(one, apiId);
                }
            });
        }
    }

    /**
     * 递归插入responseBody的下级节点
     *
     * @param responseBody
     * @param apiId
     */
    public void saveResponseChildren(SysApiResponseEntity responseBody, Long apiId) {
        if (null != responseBody.getChildren() && responseBody.getChildren().size() > 0) {
            // 获取上级主键
            Long id = responseBody.getId();
            List<SysApiResponseEntity> list = responseBody.getChildren();
            // 遍历下级所有节点
            list.forEach(one -> {
                // 存入上级节点id和apiId
                one.setParentId(id);
                one.setApiId(apiId);
                // 插入下级节点
                int insertOneCount = apiResponseDao.insertOne(one);
                if (insertOneCount < 1) {
                    throw new RuntimeException();
                }
                // 递归出口
                if (null != one.getChildren() && one.getChildren().size() > 0) {
                    this.saveResponseChildren(one, apiId);
                }
            });
        }
    }

    /**
     * 校验是否有权限查询api
     *
     * @param apiId
     * @param userId
     * @return
     */
    @DS("api")
    @Override
    public int checkApiVerify(Long apiId, long userId) {
        List<SysUserApiEntity> sysUserApiEntities = userApiDao.selectList(new QueryWrapper<SysUserApiEntity>()
                .eq("user_id", userId)
                .eq("api_id", apiId)
                .ne("is_del", 1)
                .eq("status", 1));


        return sysUserApiEntities.size();
    }

    /**
     * 根据apiId查询ApiItem
     *
     * @param apiId
     * @return
     */
    @DS("api")
    @Override
    public ApiFormDto getApiItemById(Long apiId) {

        SysApiEntity apiEntity = apiDao.selectOne(new QueryWrapper<SysApiEntity>()
        .eq("id", apiId)
        .ne("is_del",1));
        if (null == apiEntity || null == apiEntity.getId()){
            ApiFormDto apiFormDto = new ApiFormDto();
            return apiFormDto;
        }
        // 请求参数
        List<SysApiRequestQueryEntity> apiRequestQueryList = apiRequestQueryDao.selectList(new QueryWrapper<SysApiRequestQueryEntity>()
                .eq("api_id", apiId)
                .ne("is_del", 1));
        // 请求头
        List<SysApiRequestHeadersEntity> apiRequestHeadersList = apiRequestHeadersDao.selectList(new QueryWrapper<SysApiRequestHeadersEntity>()
                .eq("api_id", apiId)
                .ne("is_del", 1));
        // 请求体
        List<SysApiRequestBodyEntity> apiRequestBodyList = apiRequestBodyDao.selectList(new QueryWrapper<SysApiRequestBodyEntity>()
                .eq("api_id", apiId)
                .ne("is_del", 1)
                .isNull("parent_id"));
        // 寻找下级节点
        apiRequestBodyList.forEach(one -> {
            Long id = one.getId();
            List<SysApiRequestBodyEntity> list = apiRequestBodyDao.selectList(new QueryWrapper<SysApiRequestBodyEntity>()
                    .eq("parent_id", id)
                    .eq("api_id", apiId)
                    .ne("is_del", 1));
            list.forEach(low -> {
                Long lowId = low.getId();
                List<SysApiRequestBodyEntity> lowList = apiRequestBodyDao.selectList(new QueryWrapper<SysApiRequestBodyEntity>()
                        .eq("parent_id", lowId)
                        .eq("api_id", apiId)
                        .ne("is_del", 1));
                low.setChildren(lowList);
            });
            one.setChildren(list);
        });
        // 响应体
        List<SysApiResponseEntity> apiResponseList = apiResponseDao.selectList(new QueryWrapper<SysApiResponseEntity>()
                .eq("api_id", apiId)
                .ne("is_del", 1)
                .isNull("parent_id"));
        apiResponseList.forEach(one -> {
            Long id = one.getId();
            List<SysApiResponseEntity> list = apiResponseDao.selectList(new QueryWrapper<SysApiResponseEntity>()
                    .eq("parent_id", id)
                    .eq("api_id", apiId)
                    .ne("is_del", 1));
            list.forEach(low -> {
                Long lowId = low.getId();
                List<SysApiResponseEntity> lowList = apiResponseDao.selectList(new QueryWrapper<SysApiResponseEntity>()
                        .eq("parent_id", lowId)
                        .eq("api_id", apiId)
                        .ne("is_del", 1));
                low.setChildren(lowList);
            });
            one.setChildren(list);
        });

        ApiFormDto apiFormDto = this.getApiFormDto(apiEntity);
        apiFormDto.setRequestQueryList(apiRequestQueryList);
        apiFormDto.setRequestHeadersList(apiRequestHeadersList);
        apiFormDto.setRequestBodyList(apiRequestBodyList);
        apiFormDto.setResponseList(apiResponseList);

        return apiFormDto;
    }

    /**
     * 修改接口信息
     *
     * @param apiFormDto
     */
    @DS("api")
    @Transactional(rollbackFor = Exception.class)
    @Override
    public void updateItemByForm(ApiFormDto apiFormDto) {

        SysApiEntity sysApiEntity = this.getSysApiEntity(apiFormDto);
        this.updateById(sysApiEntity);

        // 请求头
        if (null != apiFormDto.getRequestHeadersList() && apiFormDto.getRequestHeadersList().size() > 0) {
            List<SysApiRequestHeadersEntity> requestHeadersList = apiFormDto.getRequestHeadersList();
            requestHeadersList.forEach(requestHeaders -> {
                apiRequestHeadersDao.updateById(requestHeaders);
            });
        }

        // 请求参数
        if (null != apiFormDto.getRequestQueryList() && apiFormDto.getRequestQueryList().size() > 0) {
            List<SysApiRequestQueryEntity> requestQueryList = apiFormDto.getRequestQueryList();
            requestQueryList.forEach(requestQuery -> {
                apiRequestQueryDao.updateById(requestQuery);
            });
        }

        // 请求体
        if (null != apiFormDto.getRequestBodyList() && apiFormDto.getRequestBodyList().size() > 0) {
            List<SysApiRequestBodyEntity> requestBodyList = apiFormDto.getRequestBodyList();
            requestBodyList.forEach(requestBody -> {
                apiRequestBodyDao.updateById(requestBody);
            });
        }

        // 返回数据
        if (null != apiFormDto.getResponseList() && apiFormDto.getResponseList().size() > 0) {
            List<SysApiResponseEntity> responseList = apiFormDto.getResponseList();
            responseList.forEach(response -> {
                apiResponseDao.updateById(response);
            });
        }
    }

    /**
     * 同模块下查询接口名称是否存在
     *
     * @param apiName
     * @param apiClassId
     * @return
     */
    @Override
    public int findByApiName(String apiName, Long apiClassId) {
        List<SysApiEntity> sysApiEntities = apiDao.selectListByApiName(apiName, apiClassId);

        int countByName = sysApiEntities.size();
        return countByName;
    }

    /**
     * 根据api表单Dto拆分api实体类
     *
     * @param apiFormDto
     * @return
     */
    private SysApiEntity getSysApiEntity(ApiFormDto apiFormDto) {
        SysApiEntity sysApiEntity = new SysApiEntity();

        if (null != apiFormDto.getId() && 0L < apiFormDto.getId()) {
            sysApiEntity.setId(apiFormDto.getId());
        }
        if (null != apiFormDto.getApiClassId() && 0L < apiFormDto.getApiClassId()) {
            sysApiEntity.setApiClassId(apiFormDto.getApiClassId());
        }
        if (null != apiFormDto.getApiMethod() && !"".equals(apiFormDto.getApiMethod())) {
            sysApiEntity.setApiMethod(apiFormDto.getApiMethod());
        }
        if (null != apiFormDto.getApiName() && !"".equals(apiFormDto.getApiName())) {
            sysApiEntity.setApiName(apiFormDto.getApiName());
        }
        if (null != apiFormDto.getApiRemark() && !"".equals(apiFormDto.getApiRemark())) {
            sysApiEntity.setApiRemark(apiFormDto.getApiRemark());
        }
        if (null != apiFormDto.getApiUrl() && !"".equals(apiFormDto.getApiUrl())) {
            sysApiEntity.setApiUrl(apiFormDto.getApiUrl());
        }
        if (null != apiFormDto.getStatus()) {
            sysApiEntity.setStatus(apiFormDto.getStatus());
        }
        if (null != apiFormDto.getIsDel()) {
            sysApiEntity.setIsDel(apiFormDto.getIsDel());
        }
        if (null != apiFormDto.getRequestJson() && !"".equals(apiFormDto.getRequestJson())) {
            sysApiEntity.setRequestJson(apiFormDto.getRequestJson());
        }
        if (null != apiFormDto.getResponseJson() && !"".equals(apiFormDto.getResponseJson())) {
            sysApiEntity.setResponseJson(apiFormDto.getResponseJson());
        }
        if (null != apiFormDto.getUpdateId() && 0L < apiFormDto.getUpdateId()) {
            sysApiEntity.setCreateId(apiFormDto.getUpdateId());
            sysApiEntity.setUpdateId(apiFormDto.getUpdateId());
        }
        sysApiEntity.setUpdateTime(new Date());
        sysApiEntity.setCreateTime(new Date());

        return sysApiEntity;
    }

    /**
     * 根据实体类获取DTO
     *
     * @param apiEntity
     * @return
     */
    private ApiFormDto getApiFormDto(SysApiEntity apiEntity) {
        ApiFormDto apiFormDto = new ApiFormDto();

        if (null != apiEntity.getId()) {
            apiFormDto.setId(apiEntity.getId());
        }
        if (null != apiEntity.getApiClassId()) {
            apiFormDto.setApiClassId(apiEntity.getApiClassId());
        }
        if (null != apiEntity.getApiMethod()) {
            apiFormDto.setApiMethod(apiEntity.getApiMethod());
        }
        if (null != apiEntity.getApiName()) {
            apiFormDto.setApiName(apiEntity.getApiName());
        }
        if (null != apiEntity.getApiRemark()) {
            apiFormDto.setApiRemark(apiEntity.getApiRemark());
        }
        if (null != apiEntity.getApiUrl()) {
            apiFormDto.setApiUrl(apiEntity.getApiUrl());
        }
        if (null != apiEntity.getStatus()) {
            apiFormDto.setStatus(apiEntity.getStatus());
        }
        if (null != apiEntity.getRequestJson()) {
            apiFormDto.setRequestJson(apiEntity.getRequestJson());
        }
        if (null != apiEntity.getResponseJson()) {
            apiFormDto.setResponseJson(apiEntity.getResponseJson());
        }
        if (null != apiEntity.getUpdateId() && null != apiEntity.getUpdateTime()) {
            apiFormDto.setUpdateId(apiEntity.getUpdateId());
            apiFormDto.setUpdateTime(apiEntity.getUpdateTime());
        } else if (null != apiEntity.getCreateId() && null != apiEntity.getCreateTime()) {
            apiFormDto.setUpdateId(apiEntity.getCreateId());
            apiFormDto.setUpdateTime(apiEntity.getCreateTime());
        }

        return apiFormDto;
    }

}
